package com.example.demo.game;

import com.example.demo.DemoApplication;
import com.example.demo.model.User;
import com.example.demo.service.impl.UserServiceImpl;
import com.example.demo.util.UUIDUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.media.jfxmedia.logging.Logger;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;


@Slf4j
@Data
public class Room {

    String roomId;   //房间的标识

    User user1;     //玩家1
    User user2;     //玩家2

    Long whiteUser ;  //先手方白子的用户Id

    private static final int MAX_ROW=15;
    private static final int MAX_COL=15;

    int[][] board = new int[MAX_ROW][MAX_COL];   //用0表示空（没子）；用1表示玩家1落的子，用2表示玩家2落的子
        //服务器这里设置二维数组，主要是为了判定胜负

   /* private OnLineUserManager onLineUserManager=new OnLineUserManager();*/    //这里当时出了很大的问题，就是spring管理和自己管理，出错问题就是自己在这里新new了

private  OnLineUserManager onLineUserManager;      //通过构造方法获取，构造方法我们通过再其他类中找到spring管理的这个对象，赋给它即可

    private ObjectMapper objectMapper = new ObjectMapper();

   /* private RoomManager roomManager = new RoomManager();  //与onLineUserManager同理*/
    private RoomManager roomManager;

    private UserServiceImpl userService;


    public Room(){
        roomId = UUIDUtil.getUUID_32();

        onLineUserManager = DemoApplication.context.getBean(OnLineUserManager.class);
        roomManager = DemoApplication.context.getBean(RoomManager.class);
        userService = DemoApplication.context.getBean(UserServiceImpl.class);
    }



    public void putChess(GameRequest gameRequest,Room room) throws IOException {
        //记录落子位置
        Long userId = gameRequest.getUserId();
        log.info("我们游戏房间里的用户："+user1.toString());
        log.info("我们游戏房间里的第二个用户"+user2.toString());
        log.info("cishi1111"+userId);
        int row = gameRequest.getRow();
        int col = gameRequest.getCol();
        int chess = userId==user1.getUserId()?1:2;

        if(userId==user1.getUserId()){
            if(board[row][col]!=0){
                log.info("此处已经有子了");
            }else {
                board[row][col] = 1;
            }
        }else{
            if(board[row][col]!=0){
                log.info("此处已经有子了");
            }else {
                board[row][col] = 2;
            }
        }

        printBoard();   //打印棋盘
        // 判定胜负（谁胜利返回谁的userID ;没出现胜利则返回0
      Long winnerUserId =  checkWinner(row,col,chess);


        //构造响应，返回给这个房间里的所有晚间这个响应
       GameResponse gameResponse = new GameResponse();

       gameResponse.setMessage("putChess");
       gameResponse.setRow(row);
       gameResponse.setCol(col);
       gameResponse.setUserId(userId);
       gameResponse.setWinner(winnerUserId);
      String json = objectMapper.writeValueAsString(gameResponse);

      //这里可以写当时出现的问题，我们以前这个onLineUserManager都是通过spring进行管理的，然后spring默认是单例，所以我们
        //以前通过属性注入的方式拿到的对象都是同一个，这里我们new了一个新对象，所以这里的属性的东西都不在了呀，没脑子自己，
        //没创建一个新的对象，肯定属性的东西就没有了呀；因为会开辟一个新的空间
    /*    WebSocketSession user1WebSocketSession = onLineUserManager.getUserSessionFromGameRoom(user1.getUserId());
         log.info("我们这里的色水水大大为："+user1WebSocketSession);
        WebSocketSession user2WebSocketSession = onLineUserManager.getUserSessionFromGameRoom(user2.getUserId());*/

        WebSocketSession user1WebSocketSession =roomManager.getUserSessionFromGameRoom(user1.getUserId());
        WebSocketSession user2WebSocketSession =roomManager.getUserSessionFromGameRoom(user2.getUserId());

        log.info("我们这里地对地导弹的为："+user2WebSocketSession);
        if(user1WebSocketSession==null){
            //玩家1掉线让玩家2赢
            log.info("玩家2掉线了");
            log.info(user1.toString());
            System.out.println(user2.getUserId());
            gameResponse.setWinner(user2.getUserId());
            log.info(gameResponse.toString());
            String jsn = objectMapper.writeValueAsString(gameResponse);
            userService.updateWinnerUserById(user2.getUserId());
            userService.updateLoserUserById(user1.getUserId());
            user2WebSocketSession.sendMessage(new TextMessage(jsn));
            roomManager.remove( user1.getUserId(), user2.getUserId());
            return;

        }
        if(user2WebSocketSession==null){
            log.info("玩家3掉线了");
            log.info(user2.toString());
            System.out.println(user1.getUserId());
            gameResponse.setWinner(user1.getUserId());
            log.info(gameResponse.toString());
            String jsn = objectMapper.writeValueAsString(gameResponse);

            userService.updateWinnerUserById(user1.getUserId());
            userService.updateLoserUserById(user2.getUserId());
            user1WebSocketSession.sendMessage(new TextMessage(jsn));
            roomManager.remove(user1.getUserId(), user2.getUserId());
            return;
        }
        //返回给没掉线的人即可
        if(user1WebSocketSession!=null) {

            log.info("玩家2没掉线");
            log.info(json);
            user1WebSocketSession.sendMessage(new TextMessage(json));
        }
        if(user2WebSocketSession!=null) {
            log.info("玩家3没掉线");
            log.info(json);
            user2WebSocketSession.sendMessage(new TextMessage(json));
        }
        //这样一套下来，我们就需要判定一下我们出现胜利者没有，如果出现了胜利者，就需要把这个房间销毁了

        if(gameResponse.getWinner()!=0) {
            userService.updateWinnerUserById(gameResponse.getWinner());
            Long loseUserId = user1.getUserId()== gameResponse.getWinner()?user2.getUserId():user1.getUserId();
          userService.updateLoserUserById(loseUserId);
            roomManager.remove( user1.getUserId(), user2.getUserId());
            return;

        }



    }

    private void printBoard() {

        System.out.println("打印棋盘");
        System.out.println("====================================");

        for(int r=0;r<MAX_ROW;r++){

            for(int c = 0;c<MAX_COL;c++){
                System.out.print(board[r][c]+" ");
            }
            System.out.println();
        }
        System.out.println("====================================");
    }

    private Long checkWinner(int row, int col,int chess) {

        for(int c = col-4;c<=col;c++){
            try {
                if (board[row][c] == chess &&
                        board[row][c + 1] == chess && board[row][c + 2] == chess
                        && board[row][c + 3] == chess && board[row][col + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;     //如果越界了，说明者中情况一定不会有五子出现，直接忽略即可
            }
        }

        for(int r = row-4;r<=row;r++){
            try {
                if (board[r][col] == chess && board[r + 1][col] == chess && board[r + 2][col] == chess && board[r + 3][col] == chess
                        && board[r + 4][col] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }


        //判定对角线（有两条对角线）  左对角线
        for(int r =row-4,c=col-4;r<=row&&c<=col;c++,r++){
            try {
                if (board[r][c] == chess && board[r + 1][c + 1] == chess &&
                        board[r + 2][c + 2] == chess && board[r + 3][c + 3] == chess && board[r + 4][c + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }

        for(int r =row-4,c=col+4;r<=row&&c>=col;r++,c--){
            try {
                if (board[r][c] == chess && board[r+1][c -1] == chess &&
                        board[r +2][c - 2] == chess && board[r + 3][c - 3] == chess && board[r + 4][c - 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }

        return 0L ;

    }
}
